We are going to perform an exploratory analysis of the database countries of the world.csv in order to understand the data of these countries in 2018.
23/10/2020
v1
En primer lugar, vamos a importar las librerias necesarias para nuestro analisis:
# Importamos numpy y pandas para trabajar con el DF
import numpy as np
import pandas as pd
# Importamos las librerías para hacer los plots
import matplotlib.pyplot as plt
import seaborn as sns
import chart_studio.plotly as py
import plotly.offline as pyo
import plotly.graph_objs as go
%matplotlib inline
# Importamos pandas profiling que nos permite hacer análisis exploratorios de manera automática
from pandas_profiling import ProfileReport
En segundo lugar, importamos nuestra base de datos:
data = pd.read_csv('../data/01_raw/countries of the world.csv')
data
| Country | Region | Population | Area (sq. mi.) | Pop. Density (per sq. mi.) | Coastline (coast/area ratio) | Net migration | Infant mortality (per 1000 births) | GDP ($ per capita) | Literacy (%) | Phones (per 1000) | Arable (%) | Crops (%) | Other (%) | Climate | Birthrate | Deathrate | Agriculture | Industry | Service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | ASIA (EX. NEAR EAST) | 31056997 | 647500 | 48,0 | 0,00 | 23,06 | 163,07 | 700.0 | 36,0 | 3,2 | 12,13 | 0,22 | 87,65 | 1 | 46,6 | 20,34 | 0,38 | 0,24 | 0,38 |
| 1 | Albania | EASTERN EUROPE | 3581655 | 28748 | 124,6 | 1,26 | -4,93 | 21,52 | 4500.0 | 86,5 | 71,2 | 21,09 | 4,42 | 74,49 | 3 | 15,11 | 5,22 | 0,232 | 0,188 | 0,579 |
| 2 | Algeria | NORTHERN AFRICA | 32930091 | 2381740 | 13,8 | 0,04 | -0,39 | 31 | 6000.0 | 70,0 | 78,1 | 3,22 | 0,25 | 96,53 | 1 | 17,14 | 4,61 | 0,101 | 0,6 | 0,298 |
| 3 | American Samoa | OCEANIA | 57794 | 199 | 290,4 | 58,29 | -20,71 | 9,27 | 8000.0 | 97,0 | 259,5 | 10 | 15 | 75 | 2 | 22,46 | 3,27 | NaN | NaN | NaN |
| 4 | Andorra | WESTERN EUROPE | 71201 | 468 | 152,1 | 0,00 | 6,6 | 4,05 | 19000.0 | 100,0 | 497,2 | 2,22 | 0 | 97,78 | 3 | 8,71 | 6,25 | NaN | NaN | NaN |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 222 | West Bank | NEAR EAST | 2460492 | 5860 | 419,9 | 0,00 | 2,98 | 19,62 | 800.0 | NaN | 145,2 | 16,9 | 18,97 | 64,13 | 3 | 31,67 | 3,92 | 0,09 | 0,28 | 0,63 |
| 223 | Western Sahara | NORTHERN AFRICA | 273008 | 266000 | 1,0 | 0,42 | NaN | NaN | NaN | NaN | NaN | 0,02 | 0 | 99,98 | 1 | NaN | NaN | NaN | NaN | 0,4 |
| 224 | Yemen | NEAR EAST | 21456188 | 527970 | 40,6 | 0,36 | 0 | 61,5 | 800.0 | 50,2 | 37,2 | 2,78 | 0,24 | 96,98 | 1 | 42,89 | 8,3 | 0,135 | 0,472 | 0,393 |
| 225 | Zambia | SUB-SAHARAN AFRICA | 11502010 | 752614 | 15,3 | 0,00 | 0 | 88,29 | 800.0 | 80,6 | 8,2 | 7,08 | 0,03 | 92,9 | 2 | 41 | 19,93 | 0,22 | 0,29 | 0,489 |
| 226 | Zimbabwe | SUB-SAHARAN AFRICA | 12236805 | 390580 | 31,3 | 0,00 | 0 | 67,69 | 1900.0 | 90,7 | 26,8 | 8,32 | 0,34 | 91,34 | 2 | 28,01 | 21,84 | 0,179 | 0,243 | 0,579 |
227 rows × 20 columns
Country: Listado de paises del mundo ordenados alfabéticamente.
Region: Zona geográfica dónde se encuentra el país.
Population: Población del país en habitantes.
Area (sq. mi.): Superficie del país medida en millas cuadradas.
Pop. Density (per sq. mi.): Densidad de población (habitante/sq. mi.).
Coastline (coast / area ratio): Ratio de costa en proporción al área.
Net migration: El saldo migratorio, o migración neta, es el balance que existe entre la inmigración y la emigración en un determinado lugar y en un determinado periodo de tiempo.
Infant mortality (per 1000 births): Tasa de mortalidad infantil, es decir, la cantidad de muertes por cada 1000 nacimientos.
GDP (dollar per capita): PIB per cápita
Literacy (%): Tasa de alfabetización.
Phones (per 1000): Teléfonos móviles por cada 1000 habitantes.
Arable (%): Terreno cultivale.
Crops (%): Terreno cultivado.
Other (%): Otros terrenos.
Climate: Clima del lugar.
Birhtrate: Tasa de natalidad.
Deathrate: Tasa de mortalidad.
Agriculture: Aportación del sector primario al PIB.
Industry: Aportación del sector secundario al PIB.
Service: Aportación del sector terciario al PIB.
Vamos a generar un primer EDA con la función ProfileReport para observar de manera sencilla los datos y algunos de sus gráficos.
profile = ProfileReport(data, title = "EDA of the countries")
profile
Vamos a observar de qué tipo son los datos para ver si podemos comenzar a trabajar con ellos
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 227 entries, 0 to 226 Data columns (total 20 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 Country 227 non-null object 1 Region 227 non-null object 2 Population 227 non-null int64 3 Area (sq. mi.) 227 non-null int64 4 Pop. Density (per sq. mi.) 227 non-null object 5 Coastline (coast/area ratio) 227 non-null object 6 Net migration 224 non-null object 7 Infant mortality (per 1000 births) 224 non-null object 8 GDP ($ per capita) 226 non-null float64 9 Literacy (%) 209 non-null object 10 Phones (per 1000) 223 non-null object 11 Arable (%) 225 non-null object 12 Crops (%) 225 non-null object 13 Other (%) 225 non-null object 14 Climate 205 non-null object 15 Birthrate 224 non-null object 16 Deathrate 223 non-null object 17 Agriculture 212 non-null object 18 Industry 211 non-null object 19 Service 212 non-null object dtypes: float64(1), int64(2), object(17) memory usage: 35.6+ KB
Como podemos obsrvar muchas de las columnas como Pop. Density o Coastline son tipo objeto y deberían ser de tipo float. Para solventar este problema vamos a cambiar uno a uno el tipo de columnas.
# Generamos nuestras columnas con nuevos nombres para trabajar con ellas más comodamente
data.columns = ["country", "region", "population", "area", "density", "coastline", "migration", "infant_mortality", "gdp",
"literacy", "phones", "arable", "crops", "other", "climate", "birthrate", "deathrate", "agriculture",
"industry", "service"]
# Cambiamos el tipo de columnas a float (en el caso de los datos) y category para los índices (en el caso de country y
# region) y las ',' por '.'
data.country = data.country.astype('category')
data.region = data.region.astype('category')
data.density = data.density.str.replace(",",".").astype(float)
data.coastline = data.coastline.str.replace(",",".").astype(float)
data.migration = data.migration.str.replace(",",".").astype(float)
data.infant_mortality = data.infant_mortality.str.replace(",",".").astype(float)
data.literacy = data.literacy.str.replace(",",".").astype(float)
data.phones = data.phones.str.replace(",",".").astype(float)
data.arable = data.arable.str.replace(",",".").astype(float)
data.crops = data.crops.str.replace(",",".").astype(float)
data.other = data.other.str.replace(",",".").astype(float)
data.climate = data.climate.str.replace(",",".").astype(float)
data.birthrate = data.birthrate.str.replace(",",".").astype(float)
data.deathrate = data.deathrate.str.replace(",",".").astype(float)
data.agriculture = data.agriculture.str.replace(",",".").astype(float)
data.industry = data.industry.str.replace(",",".").astype(float)
data.service = data.service.str.replace(",",".").astype(float)
# Volvemos a hacer un info para comprobar que está bien
data.info()
<class 'pandas.core.frame.DataFrame'> RangeIndex: 227 entries, 0 to 226 Data columns (total 20 columns): # Column Non-Null Count Dtype --- ------ -------------- ----- 0 country 227 non-null category 1 region 227 non-null category 2 population 227 non-null int64 3 area 227 non-null int64 4 density 227 non-null float64 5 coastline 227 non-null float64 6 migration 224 non-null float64 7 infant_mortality 224 non-null float64 8 gdp 226 non-null float64 9 literacy 209 non-null float64 10 phones 223 non-null float64 11 arable 225 non-null float64 12 crops 225 non-null float64 13 other 225 non-null float64 14 climate 205 non-null float64 15 birthrate 224 non-null float64 16 deathrate 223 non-null float64 17 agriculture 212 non-null float64 18 industry 211 non-null float64 19 service 212 non-null float64 dtypes: category(2), float64(16), int64(2) memory usage: 44.9 KB
En esta ocasión, si tenemos bien los tipos de datos, ya que aparecen como float los datos con los que trabajaremos y tenemos '.' en lugar de ','
data.head(5)
| country | region | population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | ASIA (EX. NEAR EAST) | 31056997 | 647500 | 48.0 | 0.00 | 23.06 | 163.07 | 700.0 | 36.0 | 3.2 | 12.13 | 0.22 | 87.65 | 1.0 | 46.60 | 20.34 | 0.380 | 0.240 | 0.380 |
| 1 | Albania | EASTERN EUROPE | 3581655 | 28748 | 124.6 | 1.26 | -4.93 | 21.52 | 4500.0 | 86.5 | 71.2 | 21.09 | 4.42 | 74.49 | 3.0 | 15.11 | 5.22 | 0.232 | 0.188 | 0.579 |
| 2 | Algeria | NORTHERN AFRICA | 32930091 | 2381740 | 13.8 | 0.04 | -0.39 | 31.00 | 6000.0 | 70.0 | 78.1 | 3.22 | 0.25 | 96.53 | 1.0 | 17.14 | 4.61 | 0.101 | 0.600 | 0.298 |
| 3 | American Samoa | OCEANIA | 57794 | 199 | 290.4 | 58.29 | -20.71 | 9.27 | 8000.0 | 97.0 | 259.5 | 10.00 | 15.00 | 75.00 | 2.0 | 22.46 | 3.27 | NaN | NaN | NaN |
| 4 | Andorra | WESTERN EUROPE | 71201 | 468 | 152.1 | 0.00 | 6.60 | 4.05 | 19000.0 | 100.0 | 497.2 | 2.22 | 0.00 | 97.78 | 3.0 | 8.71 | 6.25 | NaN | NaN | NaN |
Continuaremos con el tratamiento de los valores nulos, ya que como podemos observar en Andorra o American Samoa tenemos NaN
# Primero, observamos si existen valores nulos y cuántos hay en cada columna:
data.isnull().sum()
country 0 region 0 population 0 area 0 density 0 coastline 0 migration 3 infant_mortality 3 gdp 1 literacy 18 phones 4 arable 2 crops 2 other 2 climate 22 birthrate 3 deathrate 4 agriculture 15 industry 16 service 15 dtype: int64
Como podemos observar más arriba tenemos valores nulos en las columnas migration, infant_mortality, gdp, literacy, phones, arable, crop, other, climate, birhtrate, deathrate, agriculture, industry y service.
Para solucionar el problema, sustituiremos los NaN por la media de ese campo, de manera que no tendremos errores por NaN.
data.fillna(data.mean(), inplace = True)
# Comprobamos si ha cambiado, observando el df o contando los null
data.isnull().sum()
country 0 region 0 population 0 area 0 density 0 coastline 0 migration 0 infant_mortality 0 gdp 0 literacy 0 phones 0 arable 0 crops 0 other 0 climate 0 birthrate 0 deathrate 0 agriculture 0 industry 0 service 0 dtype: int64
# En esta vista podemos observar como Andorra y American Samoa tienen la media de ese campo
data.head(5)
| country | region | population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | Afghanistan | ASIA (EX. NEAR EAST) | 31056997 | 647500 | 48.0 | 0.00 | 23.06 | 163.07 | 700.0 | 36.0 | 3.2 | 12.13 | 0.22 | 87.65 | 1.0 | 46.60 | 20.34 | 0.380000 | 0.240000 | 0.380000 |
| 1 | Albania | EASTERN EUROPE | 3581655 | 28748 | 124.6 | 1.26 | -4.93 | 21.52 | 4500.0 | 86.5 | 71.2 | 21.09 | 4.42 | 74.49 | 3.0 | 15.11 | 5.22 | 0.232000 | 0.188000 | 0.579000 |
| 2 | Algeria | NORTHERN AFRICA | 32930091 | 2381740 | 13.8 | 0.04 | -0.39 | 31.00 | 6000.0 | 70.0 | 78.1 | 3.22 | 0.25 | 96.53 | 1.0 | 17.14 | 4.61 | 0.101000 | 0.600000 | 0.298000 |
| 3 | American Samoa | OCEANIA | 57794 | 199 | 290.4 | 58.29 | -20.71 | 9.27 | 8000.0 | 97.0 | 259.5 | 10.00 | 15.00 | 75.00 | 2.0 | 22.46 | 3.27 | 0.150844 | 0.282711 | 0.565283 |
| 4 | Andorra | WESTERN EUROPE | 71201 | 468 | 152.1 | 0.00 | 6.60 | 4.05 | 19000.0 | 100.0 | 497.2 | 2.22 | 0.00 | 97.78 | 3.0 | 8.71 | 6.25 | 0.150844 | 0.282711 | 0.565283 |
Nuestra base de datos ya está lista para el EDA, por lo que la guardaremos en la carpeta _lab00 > data > 02intermediate
# data.to_csv("countries_of_the_world_clean.csv")
A continuación, generamos una tabla con la información estadística más relevante que iremos comentando en los siguientes apartados con apoyo de los gráficos correspondientes.
data.describe()
| population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| count | 2.270000e+02 | 2.270000e+02 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 | 227.000000 |
| mean | 2.874028e+07 | 5.982270e+05 | 379.047137 | 21.165330 | 0.038125 | 35.506964 | 9689.823009 | 82.838278 | 236.061435 | 13.797111 | 4.564222 | 81.638311 | 2.139024 | 22.114732 | 9.241345 | 0.150844 | 0.282711 | 0.565283 |
| std | 1.178913e+08 | 1.790282e+06 | 1660.185825 | 72.286863 | 4.856710 | 35.154225 | 10026.881258 | 18.920483 | 225.965194 | 12.982573 | 8.324390 | 16.069256 | 0.664484 | 11.102286 | 4.945670 | 0.141843 | 0.133288 | 0.160243 |
| min | 7.026000e+03 | 2.000000e+00 | 0.000000 | 0.000000 | -20.990000 | 2.290000 | 500.000000 | 17.600000 | 0.200000 | 0.000000 | 0.000000 | 33.330000 | 1.000000 | 7.290000 | 2.290000 | 0.000000 | 0.020000 | 0.062000 |
| 25% | 4.376240e+05 | 4.647500e+03 | 29.150000 | 0.100000 | -0.905000 | 8.215000 | 1900.000000 | 76.400000 | 38.500000 | 3.380000 | 0.190000 | 71.985000 | 2.000000 | 12.725000 | 5.975000 | 0.040000 | 0.200000 | 0.443500 |
| 50% | 4.786994e+06 | 8.660000e+04 | 78.800000 | 0.730000 | 0.000000 | 21.050000 | 5600.000000 | 90.300000 | 181.600000 | 10.530000 | 1.080000 | 85.380000 | 2.000000 | 18.900000 | 8.170000 | 0.116000 | 0.282000 | 0.565283 |
| 75% | 1.749777e+07 | 4.418110e+05 | 190.150000 | 10.345000 | 0.980000 | 55.335000 | 15700.000000 | 97.800000 | 382.900000 | 20.000000 | 4.557111 | 95.230000 | 2.319512 | 29.770000 | 10.580000 | 0.211000 | 0.335000 | 0.671500 |
| max | 1.313974e+09 | 1.707520e+07 | 16271.500000 | 870.660000 | 23.060000 | 191.190000 | 55100.000000 | 100.000000 | 1035.600000 | 62.110000 | 50.680000 | 100.000000 | 4.000000 | 50.730000 | 29.740000 | 0.769000 | 0.906000 | 0.954000 |
A continuación, dibujaremos los histogramas de las variables numéricas, para ello seleccionaremos las variables numéricas, recordemos que en nuestro dataset tenemos tres tipos de variables:
list(set(data.dtypes.tolist()))
[dtype('float64'),
dtype('int64'),
CategoricalDtype(categories=['Afghanistan ', 'Albania ', 'Algeria ', 'American Samoa ',
'Andorra ', 'Angola ', 'Anguilla ', 'Antigua & Barbuda ',
'Argentina ', 'Armenia ',
...
'Vanuatu ', 'Venezuela ', 'Vietnam ', 'Virgin Islands ',
'Wallis and Futuna ', 'West Bank ', 'Western Sahara ',
'Yemen ', 'Zambia ', 'Zimbabwe '],
ordered=False),
CategoricalDtype(categories=['ASIA (EX. NEAR EAST) ',
'BALTICS ',
'C.W. OF IND. STATES ',
'EASTERN EUROPE ',
'LATIN AMER. & CARIB ',
'NEAR EAST ',
'NORTHERN AFRICA ',
'NORTHERN AMERICA ',
'OCEANIA ',
'SUB-SAHARAN AFRICA ',
'WESTERN EUROPE '],
ordered=False)]
# Generamos un nuevo dataframe con las variables numéricas, es decir, las float y las int64
data_num = data.select_dtypes(include = ['float64', 'int64'])
# Vemos las primeras 5 filas
data_num.head(5)
| population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 0 | 31056997 | 647500 | 48.0 | 0.00 | 23.06 | 163.07 | 700.0 | 36.0 | 3.2 | 12.13 | 0.22 | 87.65 | 1.0 | 46.60 | 20.34 | 0.380000 | 0.240000 | 0.380000 |
| 1 | 3581655 | 28748 | 124.6 | 1.26 | -4.93 | 21.52 | 4500.0 | 86.5 | 71.2 | 21.09 | 4.42 | 74.49 | 3.0 | 15.11 | 5.22 | 0.232000 | 0.188000 | 0.579000 |
| 2 | 32930091 | 2381740 | 13.8 | 0.04 | -0.39 | 31.00 | 6000.0 | 70.0 | 78.1 | 3.22 | 0.25 | 96.53 | 1.0 | 17.14 | 4.61 | 0.101000 | 0.600000 | 0.298000 |
| 3 | 57794 | 199 | 290.4 | 58.29 | -20.71 | 9.27 | 8000.0 | 97.0 | 259.5 | 10.00 | 15.00 | 75.00 | 2.0 | 22.46 | 3.27 | 0.150844 | 0.282711 | 0.565283 |
| 4 | 71201 | 468 | 152.1 | 0.00 | 6.60 | 4.05 | 19000.0 | 100.0 | 497.2 | 2.22 | 0.00 | 97.78 | 3.0 | 8.71 | 6.25 | 0.150844 | 0.282711 | 0.565283 |
Una vez tenemos nuestro dataframe numérico, podemos realizar los histogramas de estas variables:
# Con la funcion pd.hist() somos capaces de poder dibujar los histogramas de todas las variables
data_num.hist(figsize = (16, 20), bins = 50, xlabelsize = 8, ylabelsize = 8);
# Siendo:
# figsize el tamaño de la figura
# bins el número de particiones que hacemos el histograma
# _labelsize el tamaño de las etiquetas de los gráficos
En probabilidad y estadística, la correlación indica la fuerza y la dirección de una relación lineal y proporcionalidad entre dos variables estadísticas. Se considera que dos variables cuantitativas están correlacionadas cuando los valores de una de ellas varían sistemáticamente con respecto a los valores homónimos de la otra: si tenemos dos variables (A y B) existe correlación entre ellas si al disminuir los valores de A lo hacen también los de B y viceversa.
En nuestro caso, calcularemos la matriz de correlaciones y después realizaremos un mapa de calor o heatmap para entenderlo mejor.
data.corr()
| population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| population | 1.000000 | 0.469985 | -0.028190 | -0.068199 | 0.000011 | 0.022994 | -0.039319 | -0.043376 | -0.030803 | 0.188201 | -0.060741 | -0.120575 | -0.026439 | -0.045075 | -0.028354 | 0.000375 | 0.099109 | -0.080681 |
| area | 0.469985 | 1.000000 | -0.066917 | -0.095627 | 0.047442 | -0.007159 | 0.072179 | 0.035784 | 0.053360 | -0.079674 | -0.143844 | 0.138904 | -0.082128 | -0.066389 | 0.040049 | -0.050380 | 0.120907 | -0.054080 |
| density | -0.028190 | -0.066917 | 1.000000 | 0.241690 | 0.177990 | -0.144200 | 0.195751 | 0.095056 | 0.280079 | -0.080999 | -0.031655 | 0.081844 | 0.006830 | -0.159150 | -0.070022 | -0.105925 | -0.105524 | 0.187798 |
| coastline | -0.068199 | -0.095627 | 0.241690 | 1.000000 | -0.134035 | -0.136465 | 0.049109 | 0.113651 | 0.152050 | -0.120636 | 0.341433 | -0.079404 | -0.031614 | -0.075715 | -0.161703 | -0.028483 | -0.185124 | 0.181939 |
| migration | 0.000011 | 0.047442 | 0.177990 | -0.134035 | 1.000000 | -0.025015 | 0.381969 | -0.008506 | 0.239424 | -0.057689 | -0.340151 | 0.222815 | -0.014878 | -0.066523 | 0.033605 | -0.105674 | -0.023679 | 0.113697 |
| infant_mortality | 0.022994 | -0.007159 | -0.144200 | -0.136465 | -0.025015 | 1.000000 | -0.600002 | -0.745543 | -0.669715 | -0.113094 | -0.061159 | 0.123072 | -0.342848 | 0.844968 | 0.655734 | 0.697303 | 0.003510 | -0.618623 |
| gdp | -0.039319 | 0.072179 | 0.195751 | 0.049109 | 0.381969 | -0.600002 | 1.000000 | 0.497963 | 0.830549 | 0.019643 | -0.218330 | 0.097215 | 0.302404 | -0.648808 | -0.201148 | -0.570735 | -0.027935 | 0.529995 |
| literacy | -0.043376 | 0.035784 | 0.095056 | 0.113651 | -0.008506 | -0.745543 | 0.497963 | 1.000000 | 0.549913 | 0.101927 | 0.038808 | -0.102439 | 0.352569 | -0.755196 | -0.386376 | -0.585492 | 0.060661 | 0.465706 |
| phones | -0.030803 | 0.053360 | 0.280079 | 0.152050 | 0.239424 | -0.669715 | 0.830549 | 0.549913 | 1.000000 | 0.059606 | -0.149517 | 0.029317 | 0.358574 | -0.722329 | -0.259708 | -0.571704 | -0.140516 | 0.625770 |
| arable | 0.188201 | -0.079674 | -0.080999 | -0.120636 | -0.057689 | -0.113094 | 0.019643 | 0.101927 | 0.059606 | 1.000000 | 0.094361 | -0.856763 | 0.353444 | -0.183449 | 0.052991 | -0.034080 | -0.061923 | 0.088649 |
| crops | -0.060741 | -0.143844 | -0.031655 | 0.341433 | -0.340151 | -0.061159 | -0.218330 | 0.038808 | -0.149517 | 0.094361 | 1.000000 | -0.594254 | 0.004121 | 0.117851 | -0.201520 | 0.051367 | -0.113796 | 0.051980 |
| other | -0.120575 | 0.138904 | 0.081844 | -0.079404 | 0.222815 | 0.123072 | 0.097215 | -0.102439 | 0.029317 | -0.856763 | -0.594254 | 1.000000 | -0.287632 | 0.087124 | 0.061624 | 0.000954 | 0.108953 | -0.098554 |
| climate | -0.026439 | -0.082128 | 0.006830 | -0.031614 | -0.014878 | -0.342848 | 0.302404 | 0.352569 | 0.358574 | 0.353444 | 0.004121 | -0.287632 | 1.000000 | -0.427579 | 0.010458 | -0.200416 | -0.089925 | 0.260911 |
| birthrate | -0.045075 | -0.066389 | -0.159150 | -0.075715 | -0.066523 | 0.844968 | -0.648808 | -0.755196 | -0.722329 | -0.183449 | 0.117851 | 0.087124 | -0.427579 | 1.000000 | 0.395293 | 0.664903 | -0.055626 | -0.543583 |
| deathrate | -0.028354 | 0.040049 | -0.070022 | -0.161703 | 0.033605 | 0.655734 | -0.201148 | -0.386376 | -0.259708 | 0.052991 | -0.201520 | 0.061624 | 0.010458 | 0.395293 | 1.000000 | 0.376291 | 0.026527 | -0.351593 |
| agriculture | 0.000375 | -0.050380 | -0.105925 | -0.028483 | -0.105674 | 0.697303 | -0.570735 | -0.585492 | -0.571704 | -0.034080 | 0.051367 | 0.000954 | -0.200416 | 0.664903 | 0.376291 | 1.000000 | -0.322896 | -0.615556 |
| industry | 0.099109 | 0.120907 | -0.105524 | -0.185124 | -0.023679 | 0.003510 | -0.027935 | 0.060661 | -0.140516 | -0.061923 | -0.113796 | 0.108953 | -0.089925 | -0.055626 | 0.026527 | -0.322896 | 1.000000 | -0.543305 |
| service | -0.080681 | -0.054080 | 0.187798 | 0.181939 | 0.113697 | -0.618623 | 0.529995 | 0.465706 | 0.625770 | 0.088649 | 0.051980 | -0.098554 | 0.260911 | -0.543583 | -0.351593 | -0.615556 | -0.543305 | 1.000000 |
# Generamos una mask para el triángulo superior
mask = np.triu(np.ones_like(data.corr(), dtype = bool))
# np.triu(): Devuelve una copia de una matriz con los elementos debajo de la diagonal "K"-ésima en ceros.
# np.ones_like(): Devuelve un array de unos con el mismo tamaño y tipo que el array principal (data.corr())
# Generamos el tamaño de la figura
f, ax = plt.subplots(figsize=(15, 12))
# Dibujamos el mapa de calor
sns.heatmap(data.corr(), annot = True, fmt = '.1f', mask = mask, square = True, linewidths = .5, cmap = "viridis");
# annot = True/False: si queremos los valores de las correlaciones ponemos True, por defecto viene False
# fmt '.Nf' es para decir cuántos decimales queremos en cada cuadrado
# mask = ...: Si añadimos una mask, los datos no se mostrarán en las celdas donde sea True
# square = True: es para obtener cuadrados, es decir 1:1
# linewidht = N: es el ancho de la linea entre cuadrados
# cmap = "": tema que queremos escoger
# Generamos un dataset con las variables que queremos analizar con la funcion pd.loc
data_pairplot = data.loc[:,["region", "gdp", "infant_mortality", "birthrate", "phones", "literacy", "service"]]
# Realizamos un pairplot mediante la funcion de la libreria seaborn
sns.pairplot(data_pairplot, hue = "region", palette = "viridis");
# hue es la variable por la que clasificaremos
# palette es el tema de color que hemos escogido
En el gráfico situado en la parte superior tenemos el mapa de calor con las correlaciones, de esta manera podemos observar de una manera más clara las correlaciones entre las distintas variables.
Como podemos observar, la variable phones esta altamente correlacionado con gdp esto tiene sentido, ya que a mayor renta más gasto en teléfonos podemos obtener.
En el caso opuesto, es decir, correlación negativa tenemos el ejemplo de service con infant mortality , esto significa que a mayores servicios menor es la mortalidad infantil, dicho de otra manera, la sanidad forma parte del sector terciario o service , por lo que, si tenemos una mejor sanidad tendremos una menor mortalidad infantil.
Vamos a analizar el caso de la variable phones con gdp
# Dibujamos con lmplot la relación entre 'gdp' y 'phones'
sns.lmplot(x = 'gdp', y = 'phones', data = data, height = 8);
# Es importante incluir height (para establecer el tamaño) porque sino no hace el plot
Como podemos obervar en el gráfico superior, existe una correlación positiva entre teléfonos móviles por cada 1000 habitantes y la renta.
A continuación, vamos a realizar a investigar la variable regiones, de manera que podamos clasificar en siguientes apartados por regiones.
Para ello comenzaremos, averiguando cuántos países hay por región.
# Para saber cuantos países tenemos por regiones usamos value.counts()
data.region.value_counts()
SUB-SAHARAN AFRICA 51 LATIN AMER. & CARIB 45 WESTERN EUROPE 28 ASIA (EX. NEAR EAST) 28 OCEANIA 21 NEAR EAST 16 EASTERN EUROPE 12 C.W. OF IND. STATES 12 NORTHERN AFRICA 6 NORTHERN AMERICA 5 BALTICS 3 Name: region, dtype: int64
Más arriba tenemos la lista de regiones ordenada por número de países. Para tener la información de manera más visual, realizaremos un gráfico de barras:
# Definimos nuestra variable como un objeto para trabajar más cómodamente
region = data.region.value_counts()
# Generamos el tamaño de la figura
f, ax = plt.subplots(figsize=(15, 8))
# Dibujamos el gráfico, al tratarse de un gráfico de barras utilizamos sns.barplot
sns.barplot(y = region.values, x = region.index, palette = "viridis");
# Como los nombres se superponen en el gráfico, vamos a girarlos con plt.xticks(rotation = N)
plt.xticks(rotation = 90);
# Añadimos un título
plt.title('NÚMERO DE PAÍSES POR REGIÓN');
Como podemos observar la región SUB-SAHARIANA AFRICA tiene más de 50 países, seguida por LATIN AMER. & CARIB con 45, mientras que las regiones que menos países tienen son BALTICS y NORTHERN AMERICA.
Continuaremos analizando el PIB de estas 11 regiones a través de un Boxplot:
# Generamos el tamaño de la figura
f, ax = plt.subplots(figsize=(12, 12))
# Dibujamos nuestro boxplot
sns.boxplot(x = 'region', y = 'gdp', data = data, width = 0.75, palette = "viridis");
# Como los nombres se superponen en el gráfico, vamos a girarlos con plt.xticks(rotation = N)
plt.xticks(rotation = 90);
# Añadimos un título
plt.title('PIB POR REGIÓN');
En el gráfico situado más arriba tenemos los diagramas de caja del PIB de cada región. Principalmente encontramos tres grupos diferenciados:
En primer lugar, el grupo de PIB BAJO o baja renta podemos observar como la dispersión de los datos no es muy elevada comparada con los otros grupos, es decir, si nos fijamos en la morfología de los boxplots los bigotes o whiskers no se alejan de la caja en exceso, esto nos indica que la mayoría de la población se encuentra representada por el 50% de los datos.
En cuanto al grupo de PIB MEDIO o renta media encontramos una mayor dispersión de los datos, en algunos de ellos podemos observar como los datos presentan una asimetría positiva (es decir, los datos se concentran en la parte inferior de la distribución) como es el caso de ASIA (EX. NEAR EAST). En este grupo también encontramos ejemplos de asimetría negativa (los datos se encuentran en la parte superior de la distribución) como es el caso de NORTHERN AFRICA.
Por último, está el grupo de PIB ALTO o renta alta en este caso tenemos solo dos regiones NORTHERN AMERICA con una gran dispersión de los datos, es decir, encontraremos a paises con rentas por debajo de los 10000 USD y otros con rentas superiores a los 40000 USD. También tenemos a WESTERN EUROPE , esta región presenta una menor dispersión de los datos, lo que nos indica que existe una clase gran clase media que representa a la población con una renta media de 28000 USD
En el siguiente apartado analizaremos las tasas de natalidad y mortalidad, de manera que comparemos los países más pobres con los más ricos.
# Para organizar los países por riqueza tendremos que ordenar en función de la variable 'gdp'
gdp = data.sort_values(['gdp'], ascending = True)
gdp
| country | region | population | area | density | coastline | migration | infant_mortality | gdp | literacy | phones | arable | crops | other | climate | birthrate | deathrate | agriculture | industry | service | |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 58 | East Timor | ASIA (EX. NEAR EAST) | 1062777 | 15007 | 70.8 | 4.70 | 0.00 | 47.41 | 500.0 | 58.600000 | 236.061435 | 4.71 | 0.67 | 94.62 | 2.000000 | 26.99 | 6.24 | 0.085 | 0.231 | 0.684 |
| 188 | Somalia | SUB-SAHARAN AFRICA | 8863338 | 637657 | 13.9 | 0.47 | 5.37 | 116.70 | 500.0 | 37.800000 | 11.300000 | 1.67 | 0.04 | 98.29 | 1.000000 | 45.13 | 16.63 | 0.650 | 0.100 | 0.250 |
| 183 | Sierra Leone | SUB-SAHARAN AFRICA | 6005250 | 71740 | 83.7 | 0.56 | 0.00 | 143.64 | 500.0 | 31.400000 | 4.000000 | 6.98 | 0.89 | 92.13 | 2.000000 | 45.76 | 23.03 | 0.490 | 0.310 | 0.210 |
| 200 | Tanzania | SUB-SAHARAN AFRICA | 37445392 | 945087 | 39.6 | 0.15 | -2.06 | 98.54 | 600.0 | 78.200000 | 4.000000 | 4.52 | 1.08 | 94.40 | 2.139024 | 37.71 | 16.39 | 0.432 | 0.172 | 0.396 |
| 74 | Gaza Strip | NEAR EAST | 1428757 | 360 | 3968.8 | 11.11 | 1.60 | 22.93 | 600.0 | 82.838278 | 244.300000 | 28.95 | 21.05 | 50.00 | 3.000000 | 39.45 | 3.80 | 0.030 | 0.283 | 0.687 |
| ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... |
| 38 | Cayman Islands | LATIN AMER. & CARIB | 45436 | 262 | 173.4 | 61.07 | 18.75 | 8.19 | 35000.0 | 98.000000 | 836.300000 | 3.85 | 0.00 | 96.15 | 2.000000 | 12.74 | 4.89 | 0.014 | 0.032 | 0.954 |
| 22 | Bermuda | NORTHERN AMERICA | 65773 | 53 | 1241.0 | 194.34 | 2.49 | 8.53 | 36000.0 | 98.000000 | 851.400000 | 20.00 | 0.00 | 80.00 | 2.000000 | 11.40 | 7.74 | 0.010 | 0.100 | 0.890 |
| 214 | United States | NORTHERN AMERICA | 298444215 | 9631420 | 31.0 | 0.21 | 3.41 | 6.50 | 37800.0 | 97.000000 | 898.000000 | 19.13 | 0.22 | 80.65 | 3.000000 | 14.14 | 8.26 | 0.010 | 0.204 | 0.787 |
| 154 | Norway | WESTERN EUROPE | 4610820 | 323802 | 14.2 | 7.77 | 1.74 | 3.70 | 37800.0 | 100.000000 | 461.700000 | 2.87 | 0.00 | 97.13 | 3.000000 | 11.46 | 9.40 | 0.021 | 0.415 | 0.564 |
| 121 | Luxembourg | WESTERN EUROPE | 474413 | 2586 | 183.5 | 0.00 | 8.97 | 4.81 | 55100.0 | 100.000000 | 515.400000 | 23.28 | 0.40 | 76.32 | 2.139024 | 11.94 | 8.41 | 0.010 | 0.130 | 0.860 |
227 rows × 20 columns
Como podemos observar, en la parte superior están los países con menor riqueza como East Timor o Somalia, mientras que en el lado opuesto tenemos a Noruega o Luxemburgo.
A continuación, vamos a generar un gráfico interactivo con las tasas de natalidad y mortalidad infantil de los 50 países más pobres.
# Comenzamos seleccionando nuestro dataframe de los primeros 50 países en función del sort_values() que hemos hecho con gdp
df_50_poor = gdp.iloc[:50, ]
# con .iloc[] escogemos desde el 0 hasta el 50 y todas las columnas
# A continuación, definimos los parámetros del gráfico de natalidad
trace_birthrate = go.Scatter(
x = df_50_poor.gdp, # Definimos 'x' como el PIB
y = df_50_poor.birthrate, # Definimos 'y' como la tasa de natalidad
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'Tasa de natalidad', # nombre del gráfico interactivo
marker = dict(color = 'purple'), # elegimos el color
text = df_50_poor.country # text = elegimos el texto interior del gráfico
)
# Seguidamente, hacemos el de la mortalidad
trace_deathrate = go.Scatter(
x = df_50_poor.gdp, # Definimos 'x' como el PIB
y = df_50_poor.deathrate, # Definimos 'y' como la tasa de mortalidad
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'Tasa de mortalidad', # nombre del gráfico interactivo
marker = dict(color = 'darkblue'), # elegimos el color
text = df_50_poor.country # text = elegimos el texto interior del gráfico
)
# Juntamos ambos gráficos para hacer su posterior plot
birth_death = [trace_birthrate, trace_deathrate]
# Generamos el layout que queremos que tenga el gráfico a través de un diccionario
layout = dict(title = "Tasa de natalidad y mortalidad para los 50 países con menos renta per cápita",
xaxis = dict(title = "PIB per cápita")
)
# Generamos la figura con toda la información anterior
graph_50_poor_countries_birth_death = (dict(data = birth_death, layout = layout))
# Dibujamos el gráfico interactivo con la función iplot de la librería plotly offline (pyo)
pyo.iplot(graph_50_poor_countries_birth_death)
Como podemos observar en el gráfico interactivo de la parte superior, tanto la tasa de natalidad y mortalidad en los países más pobres son bastante altas, situándose la media de natalidad en torno al 35% y la de mortalidad en torno al 13%.
Una vez visto el gráfico de los 50 países más pobres, vamos a realizar el de los 50 más ricos.
# Comenzamos seleccionando nuestro dataframe de los últimos 50 países en función del sort_values() que hemos hecho con gdp
df_50_rich = gdp.iloc[(227 - 50):227, ]
# con .iloc[] escogemos desde el (227 - 50 = 177) hasta el 227, es decir, los últimos 50 países (los más ricos) del df
# A continuación, definimos los parámetros del gráfico de natalidad
trace_birthrate = go.Scatter(
x = df_50_rich.gdp, # Definimos 'x' como el PIB
y = df_50_rich.birthrate, # Definimos 'y' como la tasa de natalidad
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'Tasa de natalidad', # nombre del gráfico interactivo
marker = dict(color = 'purple'), # elegimos el color
text = df_50_rich.country # text = elegimos el texto interior del gráfico
)
# Seguidamente, hacemos el de la mortalidad
trace_deathrate = go.Scatter(
x = df_50_rich.gdp, # Definimos 'x' como el PIB
y = df_50_rich.deathrate, # Definimos 'y' como la tasa de mortalidad
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'Tasa de mortalidad', # nombre del gráfico interactivo
marker = dict(color = 'darkblue'), # elegimos el color
text = df_50_rich.country # text = elegimos el texto interior del gráfico
)
# Juntamos ambos gráficos para hacer su posterior plot
birth_death = [trace_birthrate, trace_deathrate]
# Generamos el layout que queremos que tenga el gráfico a través de un diccionario
layout = dict(title = "Tasa de natalidad y mortalidad para los 50 países con mayor renta per cápita",
xaxis = dict(title = "PIB per cápita")
)
# Generamos la figura con toda la información anterior
graph_50_rich_countries_birth_death = (dict(data = birth_death, layout = layout))
# Dibujamos el gráfico interactivo con la función iplot de la librería plotly offline (pyo)
pyo.iplot(graph_50_rich_countries_birth_death)
Sin embargo, en los países más ricos podemos observar como estas tasas son batante bajas, y se reducen conforme aumenta la renta. Así países como Luxemburgo, presentan una tasa de natalidad de casi el 12% y una de mortalidad de 8.4%
Por lo que podemos concluir, que a mayor renta menores tasa de natalidad y de mortalidad.
En este apartado trataremos de interpretar y visualizar la representación de los 3 sectores en relación al PIB. Para ello, volveremos a trabajar con nuestros dos nuevos DataFrames el de los 50 países más pobres y los 50 países más ricos, con el objetivo de explicar las diferencias existentes entre estos países.
# Comenzamos seleccionando nuestro dataframe de los últimos 50 países en función del sort_values() que hemos hecho con gdp
df_50_poor = gdp.iloc[:50, ]
# En primer lugar, definimos los parámetros del sector primario
trace_prim_sect = go.Scatter(
x = df_50_poor.gdp, # Definimos 'x' como el PIB
y = df_50_poor.agriculture, # Definimos 'y' como el sector primario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'AGRICULTURA', # nombre del gráfico interactivo
marker = dict(color = 'purple'), # elegimos el color
text = df_50_poor.country # text = elegimos el texto interior del gráfico
)
# Continuamos con el sector secundario
trace_sec_sect = go.Scatter(
x = df_50_poor.gdp, # Definimos 'x' como el PIB
y = df_50_poor.industry, # Definimos 'y' como el sector secundario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'INDUSTRIA', # nombre del gráfico interactivo
marker = dict(color = 'darkblue'), # elegimos el color
text = df_50_poor.country # text = elegimos el texto interior del gráfico
)
# Por último, hacemos el sector terciario
trace_ter_sect = go.Scatter(
x = df_50_poor.gdp, # Definimos 'x' como el PIB
y = df_50_poor.service, # Definimos 'y' como el sector secundario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'SERVICIOS', # nombre del gráfico interactivo
marker = dict(color = "seagreen"), # elegimos el color
text = df_50_poor.country # text = elegimos el texto interior del gráfico
)
# Juntamos los tres gráficos para hacer su posterior plot
prim_sec_ter = [trace_prim_sect, trace_sec_sect, trace_ter_sect]
# Generamos el layout que queremos que tenga el gráfico a través de un diccionario
layout = dict(title = "Porcentaje de los sectores económicos de los 50 países más pobres",
xaxis = dict(title = "PIB per cápita")
)
# Generamos la figura con toda la información anterior
graph_50_poor_countries_prim_sec_ter = (dict(data = prim_sec_ter, layout = layout))
# Dibujamos el gráfico interactivo con la función iplot de la librería plotly offline (pyo)
pyo.iplot(graph_50_poor_countries_prim_sec_ter)
En cuanto a la distribución de los sectores económicos vemos como es muy similar en los países pobres, estos le dan un gran peso al sector primario, en algunos casos, tanto es así que supera el 70% como es el caso de Liberia.
# Comenzamos seleccionando nuestro dataframe de los últimos 50 países en función del sort_values() que hemos hecho con gdp
df_50_rich = gdp.iloc[(227 - 50):227, ]
# En primer lugar, definimos los parámetros del sector primario
trace_prim_sect = go.Scatter(
x = df_50_rich.gdp, # Definimos 'x' como el PIB
y = df_50_rich.agriculture, # Definimos 'y' como el sector primario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'AGRICULTURA', # nombre del gráfico interactivo
marker = dict(color = 'purple'), # elegimos el color
text = df_50_rich.country # text = elegimos el texto interior del gráfico
)
# Continuamos con el sector secundario
trace_sec_sect = go.Scatter(
x = df_50_rich.gdp, # Definimos 'x' como el PIB
y = df_50_rich.industry, # Definimos 'y' como el sector secundario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'INDUSTRIA', # nombre del gráfico interactivo
marker = dict(color = 'darkblue'), # elegimos el color
text = df_50_rich.country # text = elegimos el texto interior del gráfico
)
# Por último, hacemos el sector terciario
trace_ter_sect = go.Scatter(
x = df_50_rich.gdp, # Definimos 'x' como el PIB
y = df_50_rich.service, # Definimos 'y' como el sector secundario
mode = 'lines + markers', # mode elegimos el tipo de linea, en este caso, l + p
name = 'SERVICIOS', # nombre del gráfico interactivo
marker = dict(color = 'seagreen'), # elegimos el color
text = df_50_rich.country # text = elegimos el texto interior del gráfico
)
# Juntamos los tres gráficos para hacer su posterior plot
prim_sec_ter = [trace_prim_sect, trace_sec_sect, trace_ter_sect]
# Generamos el layout que queremos que tenga el gráfico a través de un diccionario
layout = dict(title = "Porcentaje de los sectores económicos de los 50 países más ricos",
xaxis = dict(title = "PIB per cápita")
)
# Generamos la figura con toda la información anterior
graph_50_rich_countries_prim_sec_ter = (dict(data = prim_sec_ter, layout = layout))
# Dibujamos el gráfico interactivo con la función iplot de la librería plotly offline (pyo)
pyo.iplot(graph_50_rich_countries_prim_sec_ter)
En este caso, podemos observar como los 50 países más ricos tienen una distribución totalmente diferente, ya que se apoyan sobre todo en el sector servicios, parcialmente en industria y destinan menos del 10% a la agricultura.
Por lo tanto, deducimos que los países con más ricos son aquellos intensivos en el sector servicios, mientras que los países en desarrollo tienen una proporción similar en los sectores económicos.
92 Control color in seaborn heatmaps. Recuperado de https://python-graph-gallery.com/92-control-color-in-seaborn-heatmaps/Hunter
Matplotlib. Recuperado de https://matplotlib.org/McKinney
Pandas. Recuperado de https://pandas.pydata.org/docs/getting_started/index.htmlMyCS
Data visualization with plotly | Python Plotly Tutorial [Archivo de vídeo]. Recuperado de https://www.youtube.com/watch?v=87jyeklhTH8&ab_channel=MyCSOliphant
Numpy. Recuperado de https://numpy.org/Plotly
Chart-Studio. Recuperado de https://plotly.com/chart-studio/Plotly
Plotting a diagonal correlation matrix. Recuperado de https://seaborn.pydata.org/examples/many_pairwise_correlations.htmlSbrugman
pandas-profiling/pandas-profiling. Recuperado de https://github.com/pandas-profiling/pandas-profilingSeaborn
Seabron. Recuperado de https://seaborn.pydata.org/index.htmlTuatini
Detailed exploratory data analysis with python. Recuperado de https://www.kaggle.com/ekami66/detailed-exploratory-data-analysis-with-python